/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package servant;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

/**
 *
 * @author Mateusz
 */
public class XMLBuilder {

    class XMLBuilderError extends Exception {

        private String info;

        public XMLBuilderError(String info) {
            this.info = info;
//            this.infoasdf = info;
        }

        @Override
        public String toString() {
            return "XMLBuilderError{" + "info=" + info + '}';
        }
    }
    private Document document;
    private Element root;
    private Element currentSuite;
    private Element compilation;

    public XMLBuilder() throws XMLBuilderError {
        try {
            DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
            f.setNamespaceAware(true);
            f.setIgnoringElementContentWhitespace(true);
            DocumentBuilder builder = f.newDocumentBuilder();
            document = builder.newDocument();
            root = document.createElement("result");
            document.appendChild(root);
            compilation = document.createElement("compilation");
            root.appendChild(compilation);
        } catch (ParserConfigurationException ex) {
            throw new XMLBuilderError("Parser configuration error: " + ex.getMessage());
        }
    }

    public void addCompilationError(String message, String source) {
        Element errorEl = document.createElement("error");
        Element messageEl = document.createElement("message");
        Element sourceEl = document.createElement("source");
        Text messageT = document.createTextNode(message);
        Text sourceT = document.createTextNode(source);
        messageEl.appendChild(messageT);
        sourceEl.appendChild(sourceT);
        errorEl.appendChild(messageEl);
        errorEl.appendChild(sourceEl);
        compilation.appendChild(errorEl);
    }

    public void addCompilationWarning(String message, String source) {
        Element warningEl = document.createElement("warning");
        Element messageEl = document.createElement("message");
        Element sourceEl = document.createElement("source");
        Text messageT = document.createTextNode(message);
        Text sourceT = document.createTextNode(source);
        messageEl.appendChild(messageT);
        sourceEl.appendChild(sourceT);
        warningEl.appendChild(messageEl);
        warningEl.appendChild(sourceEl);
        compilation.appendChild(warningEl);
    }

    public void addTestSuie(String name, long runtime, int failures, boolean failed) throws XMLBuilderError {
        if (currentSuite != null) {
            throw new XMLBuilderError("End current suite before adding new one.");
        }
        currentSuite = document.createElement("testSuite");
        root.appendChild(currentSuite);
        currentSuite.setAttribute("count", Integer.toString(failures));
        if (failed) {
            currentSuite.setAttribute("failed", "true");
        } else {
            currentSuite.setAttribute("failed", "false");
            Element nameEl = document.createElement("name");
            Element runtimeEl = document.createElement("runtime");
            Text nameT = document.createTextNode(name);
            Text runtimeT = document.createTextNode(Long.toString(runtime));
            nameEl.appendChild(nameT);
            runtimeEl.appendChild(runtimeT);
            currentSuite.appendChild(nameEl);
            currentSuite.appendChild(runtimeEl);
        }
    }

    public void addFail(String test, String description, String message, String trace) throws XMLBuilderError {
        if (currentSuite == null) {
            throw new XMLBuilderError("No suite to add");
        }
        Element failEl = document.createElement("fail");
        Element testEl = document.createElement("test");
        Element descriptionEl = document.createElement("description");
        Element messageEl = document.createElement("message");
        Element traceEl = document.createElement("trace");
        Text testT = document.createTextNode(test);
        Text descriptionT = document.createTextNode(description);
        Text messageT = document.createTextNode(message);
        Text traceT = document.createTextNode(trace);
        testEl.appendChild(testT);
        descriptionEl.appendChild(descriptionT);
        messageEl.appendChild(messageT);
        traceEl.appendChild(traceT);
        failEl.appendChild(testEl);
        failEl.appendChild(descriptionEl);
        failEl.appendChild(messageEl);
        failEl.appendChild(traceEl);
        currentSuite.appendChild(failEl);
    }

    public void endTestSuite() throws XMLBuilderError {
        if (currentSuite == null) {
            throw new XMLBuilderError("No suite to end");
        }
        currentSuite = null;
    }

    public void endAndDump(String path) throws XMLBuilderError {
        if (currentSuite != null) {
            throw new XMLBuilderError("First end suite");
        }
        try {
            Transformer t = TransformerFactory.newInstance().newTransformer();
            t.transform(new DOMSource(document), new StreamResult(new FileOutputStream(new File(path))));
        } catch (FileNotFoundException ex) {
            throw new XMLBuilderError("File not found exception: " + path);
        } catch (TransformerException ex) {
            throw new XMLBuilderError("Transformation exception" + ex.getMessage());
        }
    }
}
